/** Java 1.3 AST Recognizer Grammar
 *
 * Author: (see java.g preamble)
 *
 * This grammar is in the PUBLIC DOMAIN
 */
class ConstantFolding extends TreeParser;

options {
	importVocab = Java;
}


{

    public void reset() {
        _currentExprValue = null;
    }

    public Object getExprValue() {
        return _currentExprValue;
    }

    // Representa o valor processado na ultima expr. E null quando nao se sabe
    // calcula-lo. Quando for um valor constante null, ai e um Object
    private Object _currentExprValue;


    private void _replaceAST(AST node, Object constant) {

        if(constant instanceof Boolean) {
            if(((Boolean)constant).booleanValue()) {
	        node.setText("true");
		node.setType(LITERAL_true);
	    }
	    else {
	        node.setText("false");
		node.setType(LITERAL_false);
	    }
	    node.setFirstChild(null);
	}
	else
	if(constant instanceof Integer) {

	}
	else
	if(constant instanceof Character) {

	}
	else
	if(constant instanceof Boolean) {

	}
	else
	if(constant instanceof String) {

	}
	else
	if(constant instanceof Float) {

	}
	else
	if(constant instanceof Double) {

	}
	else
	if(constant instanceof Long) {

	}
    }
    
    private void _oper(AST op, Object v1) {
        if(v1 == null) {
	    _currentExprValue = null;
	    return;
	}
	
	if(v1 instanceof Integer) {
	    int i1 = ((Integer)v1).intValue();
	    int res = 0;
	    switch(op.getType()) {
	        case POST_INC:
                case INC: res = i1 + 1; break;
                case POST_DEC:
		case DEC: res = i1 - 1; break;
		case UNARY_PLUS: res = +i1; break;
		case UNARY_MINUS: res = -i1; break;
	    }
	    
	    op.setType(NUM_INT);
	    op.setText(new String("" + res));
	    op.setFirstChild(null);
	    _currentExprValue = new Integer(res);
	}
	else
	if(v1 instanceof Float) {
	    float i1 = ((Float)v1).floatValue();
	    float res = 0;
	    switch(op.getType()) {
	        case POST_INC:
                case INC: res = i1 + 1; break;
                case POST_DEC:
		case DEC: res = i1 - 1; break;
		case UNARY_PLUS: res = +i1; break;
		case UNARY_MINUS: res = -i1; break;
	    }

	    op.setType(NUM_FLOAT);
	    op.setText(new String("" + res));
	    op.setFirstChild(null);
	    _currentExprValue = new Float(res);
	}
	else
	if(v1 instanceof Double) {
	    double i1 = ((Double)v1).doubleValue();
	    double res = 0;
	    switch(op.getType()) {
	        case POST_INC:
                case INC: res = i1 + 1; break;
                case POST_DEC:
		case DEC: res = i1 - 1; break;
		case UNARY_PLUS: res = +i1; break;
		case UNARY_MINUS: res = -i1; break;
	    }
	    op.setType(NUM_DOUBLE);
	    op.setText(new String("" + res));
	    op.setFirstChild(null);
	    _currentExprValue = new Double(res);
	}
	else
	if(v1 instanceof Long) {
            long i1 = ((Long)v1).longValue();
	    long res = 0;
	    switch(op.getType()) {
	    	case POST_INC:
                case INC: res = i1 + 1; break;
                case POST_DEC:
		case DEC: res = i1 - 1; break;
		case UNARY_PLUS: res = +i1; break;
		case UNARY_MINUS: res = -i1; break;
	    }

	    op.setType(NUM_LONG);
	    op.setText(new String("" + res));
	    op.setFirstChild(null);
	    _currentExprValue = new Long(res);
	}
    }

    private void _oper(AST op, Object v1, Object v2) {
        if(v1 == null || v2 == null) {
	    _currentExprValue = null;
	    return;
	}

        switch(op.getType()) {	
	    case BSR:
	    case SL:
	    case SR: _shiftFunc(op, v1, v2); break;
	}

        if(v1 instanceof Integer) {
            int i1 = ((Integer)v1).intValue();
	    if(v2 instanceof Integer) {
                int i2 = ((Integer)v2).intValue();
		
		switch(op.getType()) {		
		    case LT:
		    case GT:
		    case GE:
		    case LE: _cmpFunc(op, i1, i2); break;
		    case MOD:
		    case STAR:
		    case DIV:
		    case MINUS:
		    case PLUS: _addmultFunc(op, i1, i2); break;
		}
	    }
            else
	    if(v2 instanceof Float) {
	        float i2 = ((Float)v2).floatValue();
		
		switch(op.getType()) {
		    case LT:
		    case GT:
		    case GE:
		    case LE: _cmpFunc(op, i1, i2); break;
		    case MOD:
		    case STAR:
		    case DIV:
		    case MINUS:
		    case PLUS: _addmultFunc(op, (float)i1, i2); break;
		}
	    }
	    else
	    if(v2 instanceof Double) {
	        double i2 = ((Double)v2).doubleValue();

		switch(op.getType()) {		
		    case LT:
		    case GT:
		    case GE:
		    case LE: _cmpFunc(op, i1, i2); break;
		    case MOD:
		    case STAR:
		    case DIV:
		    case MINUS:
		    case PLUS: _addmultFunc(op, (double)i1, i2); break;
		}
            }
	    else
	    if(v2 instanceof Long) {
		long i2 = ((Long)v2).longValue();

		switch(op.getType()) {		
		    case LT:
		    case GT:
		    case GE:
		    case LE: _cmpFunc(op, i1, i2); break;
		    case MOD:
		    case STAR:
		    case DIV:
		    case MINUS:
		    case PLUS: _addmultFunc(op, (long)i1, i2); break;
		}
            }
	    else {
	        _currentExprValue = null;
	    }
	}
	else
	if(v1 instanceof Float) {
	    float i1 = ((Float)v1).floatValue();
	    if(v2 instanceof Integer) {
                int i2 = ((Integer)v2).intValue();

		switch(op.getType()) {		
		    case LT:
		    case GT:
		    case GE:
		    case LE: _cmpFunc(op, i1, i2); break;
		    case MOD:
		    case STAR:
		    case DIV:
		    case MINUS:
		    case PLUS: _addmultFunc(op, i1, (float)i2); break;
		}
	    }
            else
	    if(v2 instanceof Float) {
	        float i2 = ((Float)v2).floatValue();

		switch(op.getType()) {		
		    case LT:
		    case GT:
		    case GE:
		    case LE: _cmpFunc(op, i1, i2); break;
		    case MOD:
		    case STAR:
		    case DIV:
		    case MINUS:
		    case PLUS: _addmultFunc(op, i1, i2); break;
		}
	    }
	    else
	    if(v2 instanceof Double) {
	        double i2 = ((Double)v2).doubleValue();

		switch(op.getType()) {		
		    case LT:
		    case GT:
		    case GE:
		    case LE: _cmpFunc(op, i1, i2); break;
		    case MOD:
		    case STAR:
		    case DIV:
		    case MINUS:
		    case PLUS: _addmultFunc(op, (double)i1, i2); break;
		}
            }
	    else
	    if(v2 instanceof Long) {
		long i2 = ((Long)v2).longValue();

		switch(op.getType()) {		
		    case LT:
		    case GT:
		    case GE:
		    case LE: _cmpFunc(op, i1, i2); break;
		    case MOD:
		    case STAR:
		    case DIV:
		    case MINUS:
		    case PLUS: _addmultFunc(op, i1, (float)i2); break;
		}
            }
	    else {
	        _currentExprValue = null;
	    }
	}
	else
	if(v1 instanceof Double) {
	    double i1 = ((Double) v1).doubleValue();
	    if(v2 instanceof Integer) {
                int i2 = ((Integer)v2).intValue();
		
		switch(op.getType()) {		
		    case LT:
		    case GT:
		    case GE:
		    case LE: _cmpFunc(op, i1, i2); break;
		    case MOD:
		    case STAR:
		    case DIV:
		    case MINUS:
		    case PLUS: _addmultFunc(op, i1, (double)i2); break;
		}		
	    }
            else
	    if(v2 instanceof Float) {
	        float i2 = ((Float)v2).floatValue();

		switch(op.getType()) {		
		    case LT:
		    case GT:
		    case GE:
		    case LE: _cmpFunc(op, i1, i2); break;
		    case MOD:
		    case STAR:
		    case DIV:
		    case MINUS:
		    case PLUS: _addmultFunc(op, i1, (double)i2); break;
		}
	    }
	    else
	    if(v2 instanceof Double) {
	        double i2 = ((Double)v2).doubleValue();
		
		switch(op.getType()) {		
		    case LT:
		    case GT:
		    case GE:
		    case LE: _cmpFunc(op, i1, i2); break;
		    case MOD:
		    case STAR:
		    case DIV:
		    case MINUS:
		    case PLUS: _addmultFunc(op, i1, i2); break;
		}
            }
	    else
	    if(v2 instanceof Long) {
		long i2 = ((Long)v2).longValue();

		switch(op.getType()) {		
		    case LT:
		    case GT:
		    case GE:
		    case LE: _cmpFunc(op, i1, i2); break;
		    case MOD:
		    case STAR:
		    case DIV:
		    case MINUS:
		    case PLUS: _addmultFunc(op, i1, (double)i2); break;
		}
            }
	    else {
	        _currentExprValue = null;
	    }
	}
	else
 	if(v1 instanceof Long) {
	    long i1 = ((Long) v1).longValue();
            if(v2 instanceof Integer) {
                int i2 = ((Integer)v2).intValue();

		switch(op.getType()) {		
		    case LT:
		    case GT:
		    case GE:
		    case LE: _cmpFunc(op, i1, i2); break;
		    case MOD:
		    case STAR:
		    case DIV:
		    case MINUS:
		    case PLUS: _addmultFunc(op, i1, (long)i2); break;
		}		
	    }
            else
	    if(v2 instanceof Float) {
	        float i2 = ((Float)v2).floatValue();

		switch(op.getType()) {		
		    case LT:
		    case GT:
		    case GE:
		    case LE: _cmpFunc(op, i1, i2); break;
		    case MOD:
		    case STAR:
		    case DIV:
		    case MINUS:
		    case PLUS: _addmultFunc(op, (float)i1, i2); break;
		}
	    }
	    else
	    if(v2 instanceof Double) {
	        double i2 = ((Double)v2).doubleValue();

		switch(op.getType()) {		
		    case LT:
		    case GT:
		    case GE:
		    case LE: _cmpFunc(op, i1, i2); break;
		    case MOD:
		    case STAR:
		    case DIV:
		    case MINUS:
		    case PLUS: _addmultFunc(op, (double)i1, i2); break;
		}				       
            }
	    else
	    if(v2 instanceof Long) {
		long i2 = ((Long)v2).longValue();
		
		switch(op.getType()) {
		    case LT:
		    case GT:
		    case GE:
		    case LE: _cmpFunc(op, i1, i2); break;
		    case MOD:
		    case STAR:
		    case DIV:
		    case MINUS:
		    case PLUS: _addmultFunc(op, i1, i2); break;
		}
            }
	    else {
	        _currentExprValue = null;
	    }
	} 
	else {
	    _currentExprValue = null;
        }
    
    }

    private void _cmpFunc(AST op, double i1, double i2) {
        boolean res = false;
	switch(op.getType()) {
	    case LT: res = i1 < i2; break;
	    case GT: res = i1 > i2; break;
	    case LE: res = i1 <= i2; break;
	    case GE: res = i1 >= i2; break;
	}

	if(res) {
            op.setType(LITERAL_true);
	    op.setText("true");
	    _currentExprValue = new Boolean(true);
	}
	else {
	    op.setType(LITERAL_false);
	    op.setText("false");
	    _currentExprValue = new Boolean(false);
	}
	op.setFirstChild(null);
    }

    // So pode ser int ou long os argumentos
    private void _shiftFunc(AST op, Object v1, Object v2) {
        if(v1 == null || v2 == null) {
	    _currentExprValue = null;
	    return;
        }
    
        if(v1 instanceof Integer) {
	    int i1 = ((Integer)v1).intValue();
	    if(v2 instanceof Integer) {
	        int i2 = ((Integer)v2).intValue();

	        int res = 0;
                if(op.getType() == SL) {
		    res = i1 << i2;
		}
		else
		if(op.getType() == SR) {
		    res = i1 >> i2;
		}
		else
		if(op.getType() == BSR) {
		    res = i1 >>> i2;
		}

		op.setType(NUM_INT);
		op.setText(new String("" + res));
		op.setFirstChild(null);
		_currentExprValue = new Integer(res);
	    }
	    else {
	        long l2 = ((Long)v2).longValue();

		int res = 0;
                if(op.getType() == SL) {
		    res = i1 << l2;
		}
		else 
		if(op.getType() == SR) {
		    res = i1 >> l2;
		}
		else
		if(op.getType() == BSR) {
		    res = i1 >>> l2;
		}

		op.setType(NUM_INT);
		op.setText(new String("" + res));
		op.setFirstChild(null);
		_currentExprValue = new Integer(res);
	    }
	}
	else {
            long l1 = ((Long)v1).longValue();
	    if(v2 instanceof Integer) {
	        int i2 = ((Integer)v2).intValue();

	        long res = 0;
                if(op.getType() == SL) {
		    res = l1 << i2;
		}
		else
		if(op.getType() == SR) {
		    res = l1 >> i2;
		}
		else
		if(op.getType() == BSR) {
		    res = l1 >>> i2;
		}

		op.setType(NUM_LONG);
		op.setText(new String("" + res));
		op.setFirstChild(null);
		_currentExprValue = new Long(res);
	    }
	    else {
	        long l2 = ((Long)v2).longValue();

	        long res = 0;
                if(op.getType() == SL) {
		    res = l1 << l2;
		}
		else 
		if(op.getType() == SR) {
		    res = l1 >> l2;
		}
		else
	        if(op.getType() == BSR) {
		    res = l1 >>> l2;
		}

		op.setType(NUM_LONG);
		op.setText(new String("" + res));
		op.setFirstChild(null);
		_currentExprValue = new Long(res);
	    }
	}
    }

    private void _addmultFunc(AST op, int i1, int i2) {    
        int res = 0;
	switch(op.getType()) {
	    case PLUS: res = i1 + i2; break;
	    case MINUS: res = i1 - i2; break;
	    case DIV: res = i1 / i2; break;
	    case MOD: res = i1 % i2; break;
	    case STAR: res = i1 * i2; break;
	}	
	op.setType(NUM_INT);
	op.setText(new String("" + res));
	op.setFirstChild(null);
	_currentExprValue = new Integer(res);
    }

    private void _addmultFunc(AST op, float i1, float i2) {    
        float res = 0;
	switch(op.getType()) {
	    case PLUS: res = i1 + i2; break;
	    case MINUS: res = i1 - i2; break;
	    case DIV: res = i1 / i2; break;
	    case MOD: res = i1 % i2; break;
	    case STAR: res = i1 * i2; break;
	}
	op.setType(NUM_FLOAT);
	op.setText(new String("" + res));
	op.setFirstChild(null);
	_currentExprValue = new Float(res);
    }

    private void _addmultFunc(AST op, long i1, long i2) {
        long res = 0;
	switch(op.getType()) {
	    case PLUS: res = i1 + i2; break;
	    case MINUS: res = i1 - i2; break;
	    case DIV: res = i1 / i2; break;
	    case MOD: res = i1 % i2; break;
	    case STAR: res = i1 * i2; break;
	}
	op.setType(NUM_LONG);
	op.setText(new String("" + res));
	op.setFirstChild(null);
	_currentExprValue = new Long(res);
    }

    private void _addmultFunc(AST op, double i1, double i2) {
        double res = 0;
	switch(op.getType()) {
	    case PLUS: res = i1 + i2; break;
	    case MINUS: res = i1 - i2; break;
	    case DIV: res = i1 / i2; break;
	    case MOD: res = i1 % i2; break;
	    case STAR: res = i1 * i2; break;
	}
	op.setType(NUM_DOUBLE);
	op.setText(new String("" + res));
	op.setFirstChild(null);
	_currentExprValue = new Double(res);
    }
}


statement : 	
		variableDef
	|	#(METHOD_CALL primaryExpression elist)
	|	expression
	|	ctorCall
	;

ctorCall
	:	#( CTOR_CALL elist )
	|	#( SUPER_CTOR_CALL
			(	elist
			|	primaryExpression elist
			)
		 )
	;
	
typeSpec
	:	#(TYPE typeSpecArray)
	;

type:	identifier
	|	builtInType
	;

typeSpecArray
	:	#( ARRAY_DECLARATOR typeSpecArray )
	|	type
	;

builtInType
    :   "void"
    |   "boolean"
    |   "byte"
    |   "char"
    |   "short"
    |   "int"
    |   "float"
    |   "long"
    |   "double"
    ;

modifiers
	:	#( MODIFIERS (modifier)* )
	;

modifier
    :   "private"
    |   "public"
    |   "protected"
    |   "static"
    |   "transient"
    |   "final"
    |   "abstract"
    |   "native"
    |   "threadsafe"
    |   "synchronized"
    |   "const"
    |   "volatile"
	|	"strictfp"
    ;

parameterDef
	:	#(PARAMETER_DEF modifiers typeSpec IDENT )
	;

variableDef
	:	#(VARIABLE_DEF modifiers typeSpec variableDeclarator varInitializer)
	;

variableDeclarator
	:	IDENT
	|	LBRACK variableDeclarator
	;

varInitializer
	:	#(ASSIGN initializer)
	|
	;

initializer
	:	expression
	|	arrayInitializer
	;

arrayInitializer
	:	#(ARRAY_INIT (initializer)*)
	;


identifier   
	:	IDENT 
	|	#( DOT identifier IDENT )
	;

identifierStar
	:	IDENT
	|	#( DOT identifier (STAR|IDENT) )
	;

elist
	:	#( ELIST (expression)* )
	;

expression
	:	#(EXPR expr)
	;

expr:	#(QUESTION expr expr expr)	
	
	|	#(nasig:ASSIGN expr expr {
	
		 }) // O resultado e o da segunda expressao
	
	         // A primeira expr so pode ser um id. Entao nao da pra calcular
	|	#(PLUS_ASSIGN expr expr { _currentExprValue = null; } )

	|	#(MINUS_ASSIGN expr expr { _currentExprValue = null; } )
	
	|	#(STAR_ASSIGN expr expr { _currentExprValue = null; })

	|	#(DIV_ASSIGN expr expr { _currentExprValue = null; })

	|	#(MOD_ASSIGN expr expr { _currentExprValue = null; } )

	|	#(SR_ASSIGN expr expr { _currentExprValue = null; } )

	|	#(BSR_ASSIGN expr expr { _currentExprValue = null; } )

	|	#(SL_ASSIGN expr expr { _currentExprValue = null; } )

	|	#(BAND_ASSIGN expr expr { _currentExprValue = null; } )

	|	#(BXOR_ASSIGN expr expr { _currentExprValue = null; } )

	|	#(BOR_ASSIGN expr expr { _currentExprValue = null; } )

	|	#(nlor:LOR  { Object v1, v2; }
	             expr { v1 = _currentExprValue; }
		     expr { v2 = _currentExprValue;

		         if(v1 == null || v2 == null) {
			     _currentExprValue = null;
			 }
		         else
		         if((v1 instanceof Boolean) &&
			    (v2 instanceof Boolean) ) {

			     boolean b1 = ((Boolean)v1).booleanValue();
			     boolean b2 = ((Boolean)v2).booleanValue();

			     _currentExprValue = new Boolean(b1 | b2);	
			     _replaceAST(nlor, _currentExprValue);
			 }
			 else {
			    _currentExprValue = null;
			 }
		     }
		 )

	|	#(nland:LAND { Object v1, v2; }
	             expr { v1 = _currentExprValue; }
		     expr { v2 = _currentExprValue;

		         if(v1 == null || v2 == null) {
			     _currentExprValue = null;
			 }
		         else
		         if((v1 instanceof Boolean) &&
			    (v2 instanceof Boolean) ) {
			  
			     boolean b1 = ((Boolean)v1).booleanValue();
			     boolean b2 = ((Boolean)v2).booleanValue();
			     _currentExprValue = new Boolean(b1 & b2);			     
			     _replaceAST(nland, _currentExprValue);
			 }
			 else {
			    _currentExprValue = null;
			 }
		     }
		 )

	|	#(nbor:BOR { Object v1, v2; }
	             expr { v1 = _currentExprValue; }
		     expr { v2 = _currentExprValue;

		         if(v1 == null || v2 == null) {
			     _currentExprValue = null;
			 }
		         else		     
		         if((v1 instanceof Boolean) &&
			    (v2 instanceof Boolean) ) {
			  
			     boolean b1 = ((Boolean)v1).booleanValue();
			     boolean b2 = ((Boolean)v2).booleanValue();
			     _currentExprValue = new Boolean(b1 | b2);
                             _replaceAST(nbor, _currentExprValue);
			 }
			 else {
			    _currentExprValue = null;
			 }
		     }
	        )

	|	#(nbxor:BXOR { Object v1, v2; }
	             expr { v1 = _currentExprValue; }
		     expr { v2 = _currentExprValue;

		         if(v1 == null || v2 == null) {
			     _currentExprValue = null;
			 }
		         else		     
		         if((v1 instanceof Boolean) &&
			    (v2 instanceof Boolean) ) {
			  
			     boolean b1 = ((Boolean)v1).booleanValue();
			     boolean b2 = ((Boolean)v2).booleanValue();
			     _currentExprValue = new Boolean((b1 & !b2) | (!b1 & b2));
			     _replaceAST(nbxor, _currentExprValue);
			 }
			 else {
			    _currentExprValue = null;
			 }
		     }
		)

	|	#(nband:BAND { Object v1, v2; }
	             expr { v1 = _currentExprValue; }
		     expr { v2 = _currentExprValue;

		         if(v1 == null || v2 == null) {
			     _currentExprValue = null;
			 }
		         else		     
		         if((v1 instanceof Boolean) &&
			    (v2 instanceof Boolean) ) {

			     boolean b1 = ((Boolean)v1).booleanValue();
			     boolean b2 = ((Boolean)v2).booleanValue();
			     _currentExprValue = new Boolean(b1 & b2);
                             _replaceAST(nband, _currentExprValue);
			 }
			 else {
			    _currentExprValue = null;
			 }
		     }
	        )

	|	#(nneq:NOT_EQUAL { Object v1, v2; }

	                   expr { v1 = _currentExprValue; }
			   
			   expr { v2 = _currentExprValue;

			       if(v1 == null || v2 == null) {
			           _currentExprValue = null;
			       }
		               else
			       if(v1.getClass().equals(v2.getClass())) {
				   if(v1.equals(v2)) {
				       _currentExprValue = new Boolean(false);
				   }
				   else {
				       _currentExprValue = new Boolean(true);				   
				   }
				   _replaceAST(nneq, _currentExprValue);
			       }
			       else {
			           _currentExprValue = null;
			       }
			   }
	        )

	|	#(neq:EQUAL  { Object v1, v2; }

	                    expr { v1 = _currentExprValue; }
			    
			    expr { v2 = _currentExprValue;

			       if(v1 == null || v2 == null) {
			           _currentExprValue = null;
			       }
		               else
			       if(v1.getClass().equals(v2.getClass())) {
				   if(v1.equals(v2)) {
				       _currentExprValue = new Boolean(true);
				   }
				   else {
				       _currentExprValue = new Boolean(false); 
				   }
				   _replaceAST(neq, _currentExprValue);
			       }
			       else {
			           _currentExprValue = null;
			       }			    
			    }
	 	)

	|	#(nlt:LT { Object v1, v2; }

	       		expr { v1 = _currentExprValue; }

			expr { v2 = _currentExprValue;			
			    _oper(nlt, v1, v2);
			}
		)

	|	#(ngt:GT { Object v1, v2; }
	
			expr { v1 = _currentExprValue; }
			
			expr { v2 = _currentExprValue;
			    _oper(ngt, v1, v2);
			}
		)

	|	#(nle:LE { Object v1, v2; }

			expr { v1 = _currentExprValue; }
			
			expr { v2 = _currentExprValue;
			    _oper(nle, v1, v2);
			}
		)
	
	|	#(nge:GE { Object v1, v2; }

			expr { v1 = _currentExprValue; } 

			expr { v2 = _currentExprValue;
			       _oper(nge, v1, v2);
			}
		)

	|	#(nsl:SL { Object v1, v2; }

			expr { v1 = _currentExprValue; }
			
			expr { v2 = _currentExprValue;
			       _oper(nsl, v1, v2);
			}
		)
	
	|	#(nsr:SR { Object v1, v2; }

			expr { v1 = _currentExprValue; }

			expr { v2 = _currentExprValue;
				_oper(nsr, v1, v2);
			}
		)

	|	#(nbsr:BSR { Object v1, v2; }

			expr { v1 = _currentExprValue; }

			expr { v2 = _currentExprValue;
				_oper(nbsr, v1, v2);
			}
		)

	|	#(nplus:PLUS { Object v1, v2; }
		
			expr { v1 = _currentExprValue; }
		
			expr { v2 = _currentExprValue;
				_oper(nplus, v1, v2);
			}
		)
	
	|	#(nminus:MINUS { Object v1, v2; }

			expr { v1 = _currentExprValue; }

			expr { v2 = _currentExprValue;			
			       _oper(nminus, v1, v2);
			}
		)

	|	#(ndiv:DIV { Object v1, v2; }

			expr { v1 = _currentExprValue; }
			
			expr { v2 = _currentExprValue;
			       _oper(ndiv, v1, v2);
			}
		)
	
	|	#(nmod:MOD { Object v1, v2; }

			expr { v1 = _currentExprValue; }
			
			expr { v2 = _currentExprValue;
			       _oper(nmod, v1, v2);
			}
		)
	
	|	#(nstar:STAR { Object v1, v2; }
	
			expr { v1 = _currentExprValue; }
			
			expr { v2 = _currentExprValue;
			       _oper(nstar, v1, v2);
			}
		)

	|	#(ninc:INC 
	
			expr { 
			    _oper(ninc, _currentExprValue);
			}
		)

	|	#(ndec:DEC 
	
			expr { 
			    _oper(ndec, _currentExprValue);
			}

		)
	
	|	#(npostinc:POST_INC 
	
                        expr { 
			    _oper(npostinc, _currentExprValue);
			}			
		)
	
	|	#(npostdec:POST_DEC 

			expr { 
			    _oper(npostdec, _currentExprValue);
			}
		)
	
	|	#(nbnot:BNOT 

			expr {
			    if(_currentExprValue != null && 
			       _currentExprValue instanceof Boolean) {

			        boolean b1 = ((Boolean)_currentExprValue).booleanValue();
			        _currentExprValue = new Boolean(!b1);	
			        _replaceAST(nbnot, _currentExprValue);
			    }
			    else {
			        _currentExprValue = null;
			    }
		        }
		)
	
	|	#(nlnot:LNOT 
	
			expr {
			    if(_currentExprValue != null &&
			       _currentExprValue instanceof Boolean) {

			        boolean b1 = ((Boolean)_currentExprValue).booleanValue();
			        _currentExprValue = new Boolean(!b1);
			        _replaceAST(nlnot, _currentExprValue);
			    }
			    else {
			        _currentExprValue = null;
			    }
		        }
		)

	|	#("instanceof" expr expr { _currentExprValue = null; } )
	
	|	#(unarym:UNARY_MINUS 
			expr { 
			    _oper(unarym, _currentExprValue);
			}
		)
	
	|	#(unaryp:UNARY_PLUS 
			expr { 
			    _oper(unaryp, _currentExprValue);
			}
		)

	|	primaryExpression  // inalterado

	;


primaryExpression
    :   IDENT { _currentExprValue = null; }

    |   #(	DOT
			(	expr 
				(	IDENT
				|	arrayIndex
				|	"this"
				|	"class"
				|	#( "new" IDENT elist )
				|   "super"
				)
				
			|	#(ARRAY_DECLARATOR typeSpecArray) 
			
			|	builtInType ("class")? 
			)
		) { _currentExprValue = null; }

	|	arrayIndex { _currentExprValue = null; }

	|	#(METHOD_CALL primaryExpression elist){ _currentExprValue = null; }

	|	#(TYPECAST typeSpec expr) { _currentExprValue = null; }
	
	|   newExpression { _currentExprValue = null; }
	
	|   constant
	
    |   "super" { _currentExprValue = null; }
    
    |   "true" { _currentExprValue = new Boolean(true); }
	
    |   "false" { _currentExprValue = new Boolean(false); }

    |   "this"  { _currentExprValue = null; }

    |   "null"  { _currentExprValue = new Object(); /* e uma cte! */ }
    
	|	typeSpec // type name used with instanceof
	;


arrayIndex
	:	#(INDEX_OP primaryExpression expression)
	;

constant
    :   n1:NUM_INT  {   
    
            String s = n1.getText();
	    char [] chars = s.toCharArray();
	    if(chars.length > 2) {
	        if(chars[0] == '0' && chars[1] == 'x') {
	            s = s.substring(2);
		    _currentExprValue = new Integer(Integer.parseInt(s, 16));
	        }
	        else {
	            _currentExprValue = new Integer(s); 
  	        }
	    }
	    else {
	       _currentExprValue = new Integer(s); 
	    }
	    
	    
        }

    |   n2:CHAR_LITERAL { char [] v = n2.getText().toCharArray();
                          _currentExprValue = new Character(v[0]); }

    |   n3:STRING_LITERAL { _currentExprValue = new String(n3.getText()); }

    |   n4:NUM_FLOAT { _currentExprValue = new Float(n4.getText()); }

    |   n5:NUM_DOUBLE { _currentExprValue = new Double(n5.getText()); }

    |   n6:NUM_LONG { 

                      StringTokenizer tk = new StringTokenizer(n6.getText(), "L");		      
                      _currentExprValue = new Long(tk.nextToken()); 
		      
		    }

    ;

newExpression   
	:	#(	"new" type
			(	
			        newArrayDeclarator (arrayInitializer)?			
			|	elist (objBlock)?
			)
		)
	;

objBlock
	:	#(	OBJBLOCK
			(
				variableDef
			)*
		)
	;

newArrayDeclarator
	:	#( ARRAY_DECLARATOR (newArrayDeclarator)? (expression)? )
	;
